package top.blackr.folivora.common.core.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import top.blackr.folivora.common.core.R;

import java.sql.SQLException;
import java.util.List;

/**
 * <p>
 * 全局异常处理器
 * </p>
 */
@Slf4j
@Component
@RestController
@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalBizExceptionHandler {

    /**
     * 全局异常.
     *
     * @param e the e
     * @return R
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<String> handleGlobalException(Exception e) {
        log.error("全局未知异常信息", e);
        return R.failed();
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<String> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ignore) {
        return R.failed("暂不支持该请求方式");
    }

    @ExceptionHandler({NullPointerException.class, SQLException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<String> handleHttpRequestMethodNotSupportedException(NullPointerException e) {
        log.error("全局异常信息, {}", e.getMessage());
        return R.failed("服务器维护中，请稍后再试。");
    }


    /**
     * validation Exception
     *
     * @param exception handleBodyValidException
     * @return R
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<String> handleBodyValidException(MethodArgumentNotValidException exception) {
        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        log.warn("参数绑定异常,ex = {}", fieldErrors.get(0).getDefaultMessage());
        return R.failed(fieldErrors.get(0).getDefaultMessage());
    }

    /**
     * BizException
     *
     * @param exception -
     * @return R
     */
    @ExceptionHandler({BizException.class})
    @ResponseStatus(HttpStatus.OK)
    public R<String> handleBodyValidException(BizException exception) {
        log.error("业务未知异常：{}", exception.getMessage());
        return R.failed(exception.getMessage());
    }

    /**
     * RuntimeException
     *
     * @param exception -
     * @return R
     */
    @ExceptionHandler({RuntimeException.class})
    @ResponseStatus(HttpStatus.OK)
    public R<String> handleBodyValidException(RuntimeException exception) {
        log.error("Runtime未知异常：", exception);
        return R.failed(exception.getMessage());
    }

    @ExceptionHandler({NoResourceFoundException.class})
    @ResponseStatus(HttpStatus.OK)
    public R<String> handleNoResourceFoundException() {
        return R.failed("路径不存在");
    }

    /**
     * 避免 404 重定向到 /error 导致NPE ,ignore-url 需要配置对应端点
     *
     * @return R
     */
    @DeleteMapping("/error")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public R<String> noHandlerFoundException() {
        return R.failed(HttpStatus.NOT_FOUND.getReasonPhrase());
    }

}
